﻿using System;
using System.Collections.Generic;
using System.Linq;
using Calimbra.Runtime.Contracts;
using Calimbra.Runtime.Data;
using Calimbra.Runtime.Functions;

namespace Calimbra.Runtime
{
    public class FlowRuntime : IFlowRuntime
    {
        private readonly Dictionary<string, IOperation> operations = new Dictionary<string, IOperation>();
        private readonly List<IStream> streams = new List<IStream>();

        #region IFlowRuntime Members
        private event Action<IMessage> process;
        private event Action<IStream> addStream;
        private event Action<IOperation> addOperation;

        public FlowRuntime()
        {
            var addOp = new Add_operation();
            var addStr = new Add_stream();
            
            var map = new Map_message_to_input_ports();
            var checkOut = new Check_output();
            var determineOperation = new Determine_operation();
            var executeOperation = new Execute_operation();

            addStream = addStr.Process;
            addOperation = addOp.Process;

            process =  map.Process;
            map.Result += checkOut.Input;
            checkOut.Continue +=  determineOperation.Process;
                determineOperation.Result += executeOperation.Process;
                executeOperation.Result += map.Process;
            checkOut.Output += r => Result(r);

            addStr.Inject(streams);
            addOp.Inject(operations);
            map.Inject(streams);
            determineOperation.Inject(operations);
        }
        public void Process(IMessage message)
        {
            process(message);
        }

     
        public void AddStream(IStream stream)
        {
            addStream(stream);
        }

        public void AddStream(string fromPortName, string toPortName)
        {
            AddStream(new Stream(fromPortName, toPortName));
        }

        public void AddOperation(IOperation operation)
        {
            addOperation(operation);
        }

        public void AddOperations(IEnumerable<IOperation> operations)
        {
           operations.ToList().ForEach(AddOperation);
        }

        public event Action<IMessage> Result;
        #endregion
    }
}